const assert = function (condition, msg) {
  if (!condition) {
    throw new Error(msg)
  }
}
class Scheduler {
  constructor() {
    this.runQueue = []
    this.waitQueue = []
    this.maxRunTask = 2
  }
  addTask(timestamp = 0, str = '') {
    const toString = Object.prototype.toString
    assert(
      toString.call(timestamp) == '[object Number]',
      'timestamp must be number'
    )
    this.waitQueue.push({
      timestamp,
      str
    })
    this.runLoop()
  }
  runLoop() {
    while (
      this.runQueue.length < this.maxRunTask &&
      this.waitQueue.length > 0
    ) {
      const fn = () => {
        new Promise(resolve => {
          const task = this.waitQueue.shift()
          setTimeout(() => {
            console.log(task.str)
            resolve()
          }, task.timestamp)
        }).then(() => {
          this.runQueue = this.runQueue.filter(f => f != fn)
          this.runLoop()
        })
      }
      fn()
      this.runQueue.push(fn)
    }
  }
}

var scheduler = new Scheduler()
function addTask(timestamp, str) {
  scheduler.addTask(timestamp, str)
}
addTask(1000, '1')
addTask(500, '2')
addTask(300, '3')
addTask(400, '4')
